/* d_psg.c
 *	Client user program of distributed passenger in a train simulation
 *	
 *	Simulates a passenger
 */
 
 #include "syscall.h"
 
 /*============Global variables===============

-------Set Up Variables------------------------------
-----------------------------------------------------*/

int getOnStop[40]; /* stop to get on at*/
int getOffStop[40]; /*stop to get off at*/
int firstClass[40]; /*true if passenger is first class*/

const int MAXSTOPS = 10; /*How many Stops*/
const int MAXPASSENGERS = 30; /*Maximum Passengers*/
const int NUMBER_OF_COACHATTENDANTS = 3; /*How many Coach Attendant on the Train*/
const int NUMBER_OF_PORTERS = 3; /*How many Porters on the Train*/

/* Lock */
int ticketCheckerLineLock;
int waitingForAttendantsLock;
int coachAttendantLineLock[3];
int waitingForPortersLock;
int porterLuggageLock[3];
int waitingForTrainLock[10];

/* CV */
int ticketCheckerLine;
int ticketCheckerAvailable;
int waitingForAttendants;
int coachAttendantLine[3];
int coachAttendantAvailable[3];
int waitingForPorters;
int porterLine[3];
int porterLuggage[3];
int waitingForTrain[10];

/* MV */
int g_psgIndex;
int g_validatePsgNumber;
int psgTCWaiting[30];
int checkerBusy;
int ticketCheckerLineLength;
int tcPsgWaiting;
int validateTicketvalidated;
int numPassengersOnTrain;
int waitingToBeSatLineLength[3]; /* For CA */
int coachAttendantBusy[3];
int g_seatingPsgNumber[3];
int seatAssignment[3];
int porterLineLength[3];
int porterAvailable[3];
int passengerBeingHelped[3];

void Passenger(void);
void setupMonitors(void);
void itoa(char arr[], int size, int val);

void Dummy()
{
	PrintOut("Dummy Thread\n", 13);
    Exit(0);		
}

int main(int argc, char **argv)
{
	void (*myPsg)(void);
	void (*myDummy)(void); /*For some reason if you fork just once, nothing works*/
	
	myPsg = &Passenger;
	myDummy = &Dummy;
	
	setupMonitors(); /*Requesting all the locks, CVs, and MVs needed by Ticket Checker client*/
	Fork(myPsg);
	Fork(myDummy);

	Exit(0);
}

/*Requesting all the locks, CVs, and MVs needed by Train client*/
void setupMonitors(){
	int i;
	char indexBuf[2];
	char nameBuf[4]; /*a prefix will be put in first two slots, then the local index*/
	
	for(i=0; i<MAXSTOPS; i++)
	{
		itoa (indexBuf, 2, i);
		nameBuf[0] = 'w';
		nameBuf[1] = 't';
		nameBuf[2] = indexBuf[0];
		nameBuf[3] = indexBuf[1]; /* Example name: "wt6"*/
		
		waitingForTrain[i] = CreateCV (nameBuf, 4, 1);
		waitingForTrainLock[i] = CreateLock (nameBuf, 4, 1);
	}
	
	for (i = 0; i < MAXPASSENGERS; i ++){
		itoa (indexBuf, 2, i);
		nameBuf[0] = 'p';
		nameBuf[1] = 't';
		nameBuf[2] = indexBuf[0];
		nameBuf[3] = indexBuf[1]; /* Example name: "pt6"*/
		psgTCWaiting[i] = CreateMV (nameBuf, 4, 1);
		
		nameBuf[0] = 'p';
		nameBuf[1] = 'o'; /* getOn */
		getOnStop[i] = CreateMV(nameBuf, 4, 1);
		
		nameBuf[0] = 'p';
		nameBuf[1] = 'f'; /* getOff */
		getOffStop[i] = CreateMV(nameBuf, 4, 1);
		
		nameBuf[0] = 'f';
		nameBuf[1] = 'c'; /* firstClass */
		firstClass[i] = CreateMV(nameBuf, 4, 1);
		/*validated[i] = CreateMV(nameBuf, 4, 1);*/
	}
	
	for (i = 0; i < NUMBER_OF_COACHATTENDANTS; i ++){
		itoa (indexBuf, 2, i);
		nameBuf[0] = 'c';
		nameBuf[1] = 'a';
		nameBuf[2] = indexBuf[0];
		nameBuf[3] = indexBuf[1]; /* Example name: "ca2"*/
		
		coachAttendantLineLock[i] = CreateLock(nameBuf, 4, 1);
		
		coachAttendantLine[i] = CreateCV(nameBuf, 4, 1);
		
		nameBuf[0] = 'c';
		nameBuf[1] = 'v'; /* CA aValiable */
		coachAttendantAvailable[i] =CreateCV(nameBuf, 4, 1);
		
		waitingToBeSatLineLength[i] = CreateMV(nameBuf, 4, 1);
		
		nameBuf[0] = 'c';
		nameBuf[1] = 'b'; /* CA Busy */
		coachAttendantBusy[i] = CreateMV(nameBuf, 4, 1);
		
		nameBuf[0] = 's';
		nameBuf[1] = 'n'; /* Seat Number */
		g_seatingPsgNumber[i] = CreateMV(nameBuf, 4, 1);
		nameBuf[0] = 's';
		nameBuf[1] = 'a'; /* Seat Assignment */
		seatAssignment[i] = CreateMV(nameBuf, 4, 1);
	}
	
	for(i=0; i<NUMBER_OF_PORTERS; i++){
		itoa (indexBuf, 2, i);
		nameBuf[0] = 'p';
		nameBuf[1] = 'l';
		nameBuf[2] = indexBuf[0];
		nameBuf[3] = indexBuf[1]; /* Example name: "pl2"*/
		porterLuggageLock[i] = CreateLock(nameBuf, 4, 1);
		
		porterLine[i] = CreateCV(nameBuf, 4, 1);
		
		porterLineLength[i] = CreateMV(nameBuf, 4, 1);
		nameBuf[0] = 'p';
		nameBuf[1] = 'u'; /* Porter lUggage */
		porterLuggage[i] = CreateCV(nameBuf, 4, 1);
		nameBuf[0] = 'p';
		nameBuf[1] = 'a'; /* Porter Avaliable */
		porterAvailable[i] = CreateMV(nameBuf, 4, 1);
		nameBuf[0] = 'p';
		nameBuf[1] = 'h'; /* Psg Helped */
		passengerBeingHelped[i] =CreateMV(nameBuf, 4, 1);
	}
	
	ticketCheckerLineLock = CreateLock ("tCLineLock", 10, 0);
	waitingForAttendantsLock = CreateLock("waitingForAttenLock", 19, 1);
	waitingForPortersLock = CreateLock("wForPtsLock", 11, 1);
	
	ticketCheckerLine = CreateCV ("ticketCheckerLineCV", 19, 0);
	ticketCheckerAvailable = CreateCV("tCAvailable", 11 , 1);
	waitingForAttendants = CreateCV("waitingForAttendants", 20, 1);
	waitingForPorters = CreateCV("waitingForPorters", 17, 1);
	
	g_psgIndex = CreateMV("g_psgIndex", 10, 1); 
	g_validatePsgNumber = CreateMV("g_validatePsgNumber", 19, 1);
	checkerBusy = CreateMV("checkerBusyMV", 13, 1);
	ticketCheckerLineLength = CreateMV("ticketCheckerLL", 15, 1);
	tcPsgWaiting = CreateMV("tcPsgWaiting", 12, 1);
	validateTicketvalidated = CreateMV("vTicketvalidated", 16, 1);
	numPassengersOnTrain = CreateMV("numPsgsOnTrain",  14, 1);
	
}
void Passenger(){
	int indexOfAvailableAttendant=0;
	int indexOfSmallestAttendantLine=0;
	int indexOfSmallestPorterLine=0;
	int indexOfAvailablePorter=0;
	/*Ticket myTicket=tickets[myIdentifier];*/
	int inDC = 0; /* I'm in the Dining Car or not*/
	int isHungry = 0;
	int hasOrdered = 0; /*Whether I ordered meal yet*/
	int beenRejected = 0; /*Has been turned away from DC because it was full*/
	int newWaiter = 0; /* the sequence of picking up waiter, if no one is free*/
	int myCurrentWaiter = -1;
	char buf[2];/*Print out for Passenger Index*/
	char caBuf[2], seatBuf[3]; /*Print out for Coach Attendant & seat Number Index*/
	char waiterBuf[2]; /*Print out for Waiter Index*/
	char tempBuf[2];
	int myIdentifier = 0;
	int tcPsgW;
	myIdentifier = GetMV(g_psgIndex);
	SetMV(g_psgIndex, myIdentifier + 1);
	itoa(buf, 2 , myIdentifier);
	
	/*Acquire the lock for the train at my stop*/
	Acquire(waitingForTrainLock[GetMV(getOnStop[myIdentifier])],0);
	SetMV(psgTCWaiting[myIdentifier],1 );
	/*Wait until signalled by ticket checker that train has arrived at current stop*/
	Wait(waitingForTrain[GetMV(getOnStop[myIdentifier])],waitingForTrainLock[GetMV(getOnStop[myIdentifier])],0);
	/*Train has arrived; now exit the monitor*/
	Release(waitingForTrainLock[GetMV(getOnStop[myIdentifier])],0);
	
	/*Get in line of the Ticket Checker Line (enter Ticket Checker Monitor)*/
	Acquire(ticketCheckerLineLock,0);
	
	/*If checker is tending to someone else*/
	if( GetMV(checkerBusy) == 1){
		/*Get in line and wait*/
		SetMV(ticketCheckerLineLength, GetMV(ticketCheckerLineLength) +1);
		Wait(ticketCheckerLine, ticketCheckerLineLock,0);
		SetMV(ticketCheckerLineLength, GetMV(ticketCheckerLineLength) - 1);
	}
	else/*Ticket Checker isn't busy so now setting him to busy*/
		SetMV(checkerBusy, 1);
	
	/*Telling Ticket Checker I'm ready to interact*/
	/*Begin validating ticket; make my ticket data available*/
	SetMV(g_validatePsgNumber, myIdentifier);
	tcPsgW = GetMV(tcPsgWaiting);
	while( tcPsgW ==0){ /*wait for TC to have "wait" ready)*/
		/*Wait(ticketCheckerAvailable, ticketCheckerLineLock,0);*/
	}
	SetMV(tcPsgWaiting, 0);
	/*Signal Ticket Checker to verify*/
	Signal(ticketCheckerAvailable, ticketCheckerLineLock,0);
	SetMV(psgTCWaiting[myIdentifier], 1);
	/*Wait on Ticket Checker to verify*/
	Wait(ticketCheckerAvailable, ticketCheckerLineLock,0);
	/*Check to see what Ticket Checker decided*/
	if( GetMV(validateTicketvalidated) == 0){/*Ticket data was not valid*/
		PrintOut("Passenger [", 11);
		PrintOut(buf, 2);
		PrintOut("] of Train [0] has a [invalid] ticket\n", 38);
		/*SetMV(validated[myIdentifier], 0);*/
		/*Release my lock on the Ticket Checker*/
		Release(ticketCheckerLineLock, 0);
	}
	else{
		/*Ticket data was valid; I can board*/
		PrintOut("Passenger [", 11);
		PrintOut(buf , 2);
		PrintOut("] of Train [0] has a [valid] ticket\n", 36);
		SetMV(numPassengersOnTrain, GetMV(numPassengersOnTrain) + 1);
		/*SetMV(validated[myIdentifier], 1);*/
		/*Enter the Seat Assignment monitor*/
		/*If not the last person to be assigned a ticket*/
		Release(ticketCheckerLineLock,0);
		Acquire(waitingForAttendantsLock,0);
		
		for(indexOfAvailableAttendant=0;indexOfAvailableAttendant<NUMBER_OF_COACHATTENDANTS;indexOfAvailableAttendant++)
		{
			if (GetMV(waitingToBeSatLineLength[indexOfSmallestAttendantLine])>GetMV(waitingToBeSatLineLength[indexOfAvailableAttendant]))
				indexOfSmallestAttendantLine=indexOfAvailableAttendant;
			if(GetMV(coachAttendantBusy[indexOfAvailableAttendant]) == 0)
			{
				SetMV(coachAttendantBusy[indexOfAvailableAttendant], 1);
				break;	
			}
		}
		
		/*If Coach Attendant is tending to someone else*/
		if (indexOfAvailableAttendant==NUMBER_OF_COACHATTENDANTS)
		{
			indexOfAvailableAttendant=indexOfSmallestAttendantLine;
			/*Enter the Coach Attendant Monitor*/
			SetMV(waitingToBeSatLineLength[indexOfAvailableAttendant], GetMV(waitingToBeSatLineLength[indexOfAvailableAttendant]) +1);
			Wait(waitingForAttendants, waitingForAttendantsLock,0);
			Release(waitingForAttendantsLock,0);
		
			Acquire(coachAttendantLineLock[indexOfAvailableAttendant]);
			/*Add myself to the line for Coach Attendants and wait*/
		
			Wait(coachAttendantLine[indexOfAvailableAttendant], coachAttendantLineLock[indexOfAvailableAttendant],0);
			SetMV(waitingToBeSatLineLength[indexOfAvailableAttendant], GetMV(waitingToBeSatLineLength[indexOfAvailableAttendant]) -1);
		}
		else/*Coach Attendant isn't busy so now setting him to busy and moving on*/
		{
			SetMV(waitingToBeSatLineLength[indexOfAvailableAttendant], GetMV(waitingToBeSatLineLength[indexOfAvailableAttendant]) +1);
			Wait(waitingForAttendants, waitingForAttendantsLock,0);
			Release(waitingForAttendantsLock,0);
			Acquire(coachAttendantLineLock[indexOfAvailableAttendant],0);
			SetMV(waitingToBeSatLineLength[indexOfAvailableAttendant], GetMV(waitingToBeSatLineLength[indexOfAvailableAttendant]) -1);
		}
		/*Telling Coach Attendant I'm ready to interact*/
		/*Getting seat assignment; make my ticket data available*/
		SetMV(g_seatingPsgNumber[indexOfAvailableAttendant], myIdentifier);
		/*Signal Coach Attendant to verify*/
		Signal(coachAttendantAvailable[indexOfAvailableAttendant], coachAttendantLineLock[indexOfAvailableAttendant],0);
		/*Wait on Coach Attendants' response*/
		Wait(coachAttendantAvailable[indexOfAvailableAttendant], coachAttendantLineLock[indexOfAvailableAttendant],0);
		
		itoa(caBuf, 2 , indexOfAvailableAttendant);
		itoa(seatBuf, 3 , GetMV(seatAssignment[indexOfAvailableAttendant]));
		PrintOut("Passenger [", 11);
		PrintOut(buf, 2);
		PrintOut("] of Train [0] is given seat number [", 37);
		PrintOut(seatBuf, 3);
		PrintOut("] by the Coach Attendant [",26);
		PrintOut(caBuf, 2);
		PrintOut("]\n", 2);
		
		/*If I'm a first class passenger enter the porter monitor*/
		if (GetMV(firstClass[myIdentifier]) == 1)
		{
			Acquire(waitingForPortersLock,0);
			/*Exit Coach Attendant monitor*/
			Release(coachAttendantLineLock[indexOfAvailableAttendant],0);
			
			for(indexOfAvailablePorter=0;indexOfAvailablePorter<NUMBER_OF_PORTERS;indexOfAvailablePorter++)
			{
				if(GetMV(porterLineLength[indexOfSmallestPorterLine])>GetMV(porterLineLength[indexOfAvailablePorter]))
					indexOfSmallestPorterLine=indexOfAvailablePorter;
				if(GetMV(porterAvailable[indexOfAvailablePorter]))
				{
					SetMV(porterAvailable[indexOfAvailablePorter], 0);
					break;
				}
			}
			if (indexOfAvailablePorter==NUMBER_OF_PORTERS)
			{
				indexOfAvailablePorter=indexOfSmallestPorterLine;
				SetMV(porterLineLength[indexOfAvailablePorter], GetMV(porterLineLength[indexOfAvailablePorter])+1);
				Signal(waitingForPorters, waitingForPortersLock,0);
				Wait(waitingForPorters, waitingForPortersLock,0);
				Release(waitingForPortersLock,0);
				Acquire(porterLuggageLock[indexOfAvailablePorter],0);
				Wait(porterLine[indexOfAvailablePorter], porterLuggageLock[indexOfAvailablePorter],0);
				SetMV(porterLineLength[indexOfAvailablePorter], GetMV(porterLineLength[indexOfAvailablePorter])-1);
			}
			else
			{
				SetMV(porterLineLength[indexOfAvailablePorter], GetMV(porterLineLength[indexOfAvailablePorter])+1);
				Signal(waitingForPorters, waitingForPortersLock,0);
				Wait(waitingForPorters, waitingForPortersLock,0);
				Release(waitingForPortersLock,0);
				Acquire(porterLuggageLock[indexOfAvailablePorter],0);
				SetMV(porterLineLength[indexOfAvailablePorter], GetMV(porterLineLength[indexOfAvailablePorter])-1);
			}
			/*Let porter know who I am*/
			SetMV(passengerBeingHelped[indexOfAvailablePorter], myIdentifier);
			Signal(porterLuggage[indexOfAvailablePorter],porterLuggageLock[indexOfAvailablePorter],0);
			Wait(porterLuggage[indexOfAvailablePorter], porterLuggageLock[indexOfAvailablePorter],0);
			/*Exit monitor*/
			Release(porterLuggageLock[indexOfAvailablePorter],0);
		}
		else
			Release(coachAttendantLineLock[indexOfAvailableAttendant],0);
			
		/*while(currentStop < MAXSTOPS)
		{
			Dining Car Codes
		}*/
	}
	Exit(0);
}

int myexp ( int count ) {
  int i, val=1;
  for (i=0; i<count; i++ ) {
    val = val * 10;
  }
  return val;
}

void itoa( char arr[], int size, int val ) {
  int i, max, dig, subval, loc;
  for (i=0; i<size; i++ ) {
    arr[i] = '\0';
  }

  for ( i=1; i<=10; i++ ) {
    if (( val / myexp(i) ) == 0 ) {
      max = i-1;
      break;
    }
  }

  subval = 0;
  loc = 0;
  for ( i=max; i>=0; i-- ) {
    dig = 48 + ((val-subval) / myexp(i));
    subval += (dig-48) * myexp(i);
    arr[loc] = dig;
    loc++;
  }

  return;
}
